package com.michaelbulava.TFS.tasks.connect;

import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FilePath;
import com.michaelbulava.TFS.Messages;
import com.michaelbulava.TFS.persistence.IdeaPersistenceStoreProvider;
import com.michaelbulava.TFS.tasks.BackgroundableTask;
import com.michaelbulava.TFS.vcs.utils.TFSFileUtil;
import com.michaelbulava.TFS.vcs.utils.TFSProgressUtil;
import com.microsoft.tfs.core.TFSTeamProjectCollection;
import com.microsoft.tfs.core.clients.versioncontrol.Workstation;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.WorkingFolder;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace;
import com.microsoft.tfs.core.clients.versioncontrol.workspacecache.WorkspaceInfo;
import com.microsoft.tfs.util.Check;

import java.text.MessageFormat;
import java.util.Collection;
import java.util.List;

/**
 * Created by MichaelA on 9/22/2015.
 */
public class InitializeModuleWorkspaceTask extends BackgroundableTask {

    public interface ModuleWorkspaceInitializeCallbacks{

        Collection<Workspace> getAssociatedWorkspaces();

        boolean isWorkspaceOnline(Workspace workspace);

        void TaskStarting();

        void TaskCompleted(Module module, Workspace workspace, boolean isOnline);
    }

    private final Module myModule;
    private final ModuleWorkspaceInitializeCallbacks callbacks;

    private final WorkspaceInfo workspaceInfo;
    private final boolean useOffline;

    private Workspace workspace;
    private boolean workspaceIsOnline;


    public InitializeModuleWorkspaceTask(Module module, WorkspaceInfo workspaceInfo, boolean isOffline,
                                         ModuleWorkspaceInitializeCallbacks workerCallbacks) {
        super(module.getProject(),
                MessageFormat.format(Messages.getString("ConnectModuleToWorkspaceTask.Title_FORMAT"),
                        new Object[]{ module.getName() }), true);
        Check.notNull(workerCallbacks, "workerCallbacks");
        Check.notNull(workspaceInfo, "workspaceInfo");
        this.myModule = module;
        this.callbacks = workerCallbacks;
        this.workspaceInfo = workspaceInfo;
        this.useOffline = isOffline;
    }

    @Override
    protected boolean runInBackground() {
        return true;
    }

    @Override
    public void run(ProgressIndicator indicator) {
        try{
            callbacks.TaskStarting();
        } catch(Throwable tr){
            throw new RuntimeException("implementations of ModuleWorkspaceInitializeCallbacks.TaskStarting, must guard against exceptions, task cannot continue", tr);
        }
        try{
            TFSProgressUtil.setProgressText(indicator, Messages.getString("ConnectModuleToWorkspaceTask.Step1"));
            Collection<Workspace> knownWorkspaces = callbacks.getAssociatedWorkspaces();
            boolean foundAndHandled = false;
            for(Workspace workspace : knownWorkspaces){
                if (workspace.getServerURI() == workspaceInfo.getServerURI() &&
                        workspace.getDisplayName() == workspaceInfo.getDisplayName()){
                    //This is probably the right workspace but lets double check.
                    WorkingFolder[] folders = workspace.getFolders();
                    for(int i = 0; i < folders.length; i++){
                        FilePath mappedFolder = TFSFileUtil.getFilePath(folders[i].getLocalItem());
                        if (TFSFileUtil.getFilePath(myModule.getModuleFile()).isUnder(mappedFolder, true)){
                            //Confirmed this matches up with the workspace.
                            //Now do the workspace's online state match

                            //UseOffline and ModuleWorkspaceInitializeCallbacks.isWorkspaceOnline are backwards
                            //from each other, so we can only reuse the workspace if the values match, otherwise
                            // someone needs to flip modes
                            if(useOffline != callbacks.isWorkspaceOnline(workspace)){
                                this.workspace = workspace;
                                workspaceIsOnline =  callbacks.isWorkspaceOnline(workspace);

                                foundAndHandled = true;
                                break;
                            } else{
                                //TODO HANDLE this?
                                throw new RuntimeException("Mix Matched State for same Workspace");
                            }
                        }
                    }
                }
                if (foundAndHandled)
                    break;
            }
            TFSProgressUtil.setProgressText(indicator,
                    MessageFormat.format(Messages.getString("ConnectModuleToWorkspaceTask.Step2")
                            , new Object[] { workspaceInfo.getServerURI() }));
            if (this.workspace == null){
                ConnectToCollectionTask connectTask = new ConnectToCollectionTask(myProject, workspaceInfo.getServerURI()) {
                    @Override
                    protected boolean runInBackground() {
                        return false;
                    }
                };
                connectTask.authenticateConnection(!useOffline);
                connectTask.run(indicator);

                TFSTeamProjectCollection collection = (TFSTeamProjectCollection)connectTask.getConnection();
                this.workspace = workspaceInfo.getWorkspace(collection);

                this.workspaceIsOnline = collection.hasAuthenticated();

                if (collection.hasAuthenticated()){
                    //since we're connected update the workspaceinfo cache, for the server.
                    Workstation.getCurrent(IdeaPersistenceStoreProvider.INSTANCE)
                            .updateWorkspaceInfoCache(collection.getVersionControlClient(),
                                    collection.getAuthorizedTFSUser().toString());
                }

            }
        }catch(Throwable tr){
            throw new RuntimeException("Failure in InitializeModuleWorkspaceTask", tr);
        }finally {
            callbacks.TaskCompleted(myModule, workspace, workspaceIsOnline);
        }
    }

}
